<template>
    <div class="v-table" :class="[readonly ? 'list' : 'editor']">
        <div class="v-table__header">
            <div
                v-for="(col, idx) in currentColumns"
                :key="idx"
                :class="['v-table__header-item', 'cell', col.align ? col.align : '']"
                :style="getColumnStyles(col, idx)"
                @click="e => handleSort(e, col.prop, idx)"
            >
                <template v-if="col.isIcon">
                    <i :class="col.label"></i>
                </template>

                <template v-else>{{ col.label }}</template>

                <template v-if="orderBy === col.prop">
                    <i v-if="sortType === 'asc'" class="icon icon-sort-asc"></i>
                    <i v-else class="icon icon-sort-desc"></i>
                </template>
            </div>
            <template v-if="!readonly && !disableOperations">
                <div class="v-table__header-item cell" :style="getColumnStyles()">
                    <i class="icon icon-setting"></i>
                    <!--<template>operation</template>-->
                </div>
            </template>
        </div>
        <div class="v-table__shadow"></div>
        <div ref="rowBox" class="v-table__row-box">
            <!-- loop row -->
            <template v-for="(row, ridx) in currentValue" :key="'r' + ridx">
                <div :class="getRowClasses(row)" @click="handleSelectRow(row, ridx)">
                    <!-- loop column -->
                    <div
                        v-for="(col, cidx) in row"
                        :key="'c' + ridx + '-' + cidx"
                        class="v-table__cell"
                        :class="getColumnClasses(currentColumns[cidx], ridx)"
                        :style="getColumnStyles(currentColumns[cidx], ridx)"
                    >
                        <!-- editor's style -->
                        <template v-if="!readonly">
                            <slot name="field" :props="{ ridx: ridx, cidx: cidx, col: currentColumns[cidx] }">
                                <v-field
                                    :type="currentColumns[cidx] ? currentColumns[cidx]['type'] : ''"
                                    :idx="ridx"
                                    :name="currentColumns[cidx] ? currentColumns[cidx]['prop'] : ''"
                                    v-model="currentValue[ridx][cidx]"
                                    :options="
                                        options && currentColumns[cidx] ? options[currentColumns[cidx]['prop']] : []
                                    "
                                    :validator="currentColumns[cidx] && currentColumns[cidx]['validator']"
                                />
                            </slot>
                        </template>

                        <!-- list's style -->
                        <template v-else>
                            <!-- selected or unselected -->
                            <template v-if="currentColumns[cidx] && currentColumns[cidx]['prop'] == 'checkbox'">
                                <i :class="getRowClasses(row, 'icon')"></i>
                            </template>
                            <!-- lock or unlock -->
                            <!-- <template v-else-if="currentColumns[cidx]['prop'] == 'properties.lock'">
                                <i :class="['icon', {'icon-lock': col.value == 'true'}, { 'icon-unlock': col.value == 'false' }]"></i>
                            </template> -->
                            <template v-else-if="currentColumns[cidx] && currentColumns[cidx]['isIcon']">
                                <i :class="['status', 'icon', col]"></i>
                            </template>
                            <template v-else-if="typeof col === 'object'">
                                {{ col.value ? col.value : '' }}
                            </template>
                            <!-- if checkbox, show icon -->
                            <template
                                v-else-if="
                                    currentColumns[cidx].type === 'checkbox' || currentColumns[cidx].type === 'radio'
                                "
                            >
                                <i v-if="col" class="icon icon-checked"></i>
                            </template>
                            <!-- if select, show options label -->
                            <template v-else-if="currentColumns[cidx].type === 'select'">
                                {{ getSelectText(cidx, col) }}
                            </template>
                            <!-- normal content -->
                            <template v-else>{{ col }}</template>
                        </template>
                    </div>

                    <template v-if="!readonly && !disableOperations">
                        <div class="v-table__cell" :style="getColumnStyles()">
                            <i class="icon icon-add" @click="e => handleOperateClick(e, 'add', ridx)"></i>
                            <i class="icon icon-subtract" @click="e => handleOperateClick(e, 'subtract', ridx)"></i>
                        </div>
                    </template>
                </div>
            </template>
        </div>
    </div>
</template>

<script>
import { mapState } from 'vuex';
import vField from './v-field.vue';
import bus from './Eventbus.js';
// import Tic from '../vendors/Tic.js';
// import * as Utils from '../js/Utils.js';

/**
 * v-table
 */
export default {
    name: 'v-table',
    components: { vField }, //eslint-disable-line
    props: {
        id: String,
        module: String,
        columns: {
            type: Array,
            default: () => []
        },
        value: {
            type: Array,
            default: () => []
        },
        func: Function,
        readonly: Boolean,
        options: {
            type: Object,
            default: () => {}
        },
        lockColumnDisabled: Boolean,
        modifiedColumnDisabled: Boolean,
        responsibilityColumnDisabled: Boolean,
        isActive: Boolean,
        selectedIds: {
            type: Array,
            default: () => []
        },
        disableOperations: Boolean
    },
    data() {
        return {
            trueName: this.id || this.$options.name + '.' + this._uid,
            currentColumns: this.columns,
            currentValue: this.value,
            originalValue: [],
            currentIds: this.selectedIds,
            selectedRowIdx: -1,
            orderBy: '',
            sortType: '',
            page: 1,
            limit: parseInt(process.env.VUE_APP_LIMIT)
        };
    },
    computed: {
        ...mapState({
            isAltFnActive: state => state.businessStatus.isAltFnActive
        }),
        selectedAll() {
            return this.currentIds.length === this.currentValue.length;
        },
        columnsWidth() {
            let rtn = 0;
            this.currentColumns.every(c => (c.width ? (rtn = rtn + c.width) : 0));
            return rtn;
        }
    },
    watch: {
        // value: { handler (val) { this.currentValue = val; }, deep:  true },
        value(val) {
            this.currentValue = val;
            if (!this.readonly && this.currentValue.length < 1) this.addByIdx(this.currentValue.length - 1);
        },
        currentValue(val) {
            // console.log('v-table.watch.currentValue: ', val);
            this.$emit('input', val);
        },
        selectedIds: {
            handler(val) {
                this.currentIds = val;
            },
            deep: true
        },
        currentIds(val) {
            this.$emit('handleSelect', val, this.module);

            if (val && val.length) {
                let lastId = val[val.length - 1],
                    lastIdx = this.originalValue.findIndex(o => o.id === lastId),
                    boxTop = this.$refs.rowBox.offsetTop,
                    row = this.$refs.rowBox.children[lastIdx],
                    rowTop = row ? row.offsetTop : 0,
                    h = this.$refs.rowBox.offsetHeight;
                if (Math.abs(rowTop - boxTop - this.$refs.rowBox.scrollTop) >= h)
                    this.$refs.rowBox.scrollTop = rowTop - boxTop || 0;
            }
        }
    },
    created() {
        // bus.on('v-table.toggleSelectAll', this.toggleSelectAll);
        bus.on(`${this.trueName}.repaint`, this.repaint);
        bus.on(`${this.trueName}.toggleSelectAll`, this.toggleSelectAll);
        // bus.on(`${this.trueName}.selectRow`, this.selectRow);
        // bus.on(`${this.trueName}.deselectRow`, this.deselectRow);
    },
    beforeDestroy: function() {
        // 清除事件监听
        // bus.off('v-table.toggleSelectAll', this.toggleSelectAll);
        bus.off(`${this.trueName}.repaint`, this.repaint);
        bus.off(`${this.trueName}.toggleSelectAll`, this.toggleSelectAll);
        // bus.off(`${this.trueName}.selectRow`, this.selectRow);
        // bus.off(`${this.trueName}.deselectRow`, this.deselectRow);

        if (this.tic) this.tic.clear();
    },
    mounted() {
        this.init();
    },
    methods: {
        async init() {
            if (this.tic) this.tic.clear();
            this.page = 1;
            this.originalValue = [];
            this.currentColumns = this.columns || [];
            this.currentValue = this.value || [];

            await this.getList();

            if (!this.readonly && this.currentValue.length < 1) this.addByIdx(this.currentValue.length - 1);
            // console.log(`v-table.${this._uid}.init: `, this.readonly, this.currentValue);
        },
        getColumnStyles(col = { width: 100 }) {
            let rtn = {
                width: (col ? col.width : 0) + 'px',
                display: col.width === 0 ? 'none' : ''
            };
            let totalWidth = (this.$el && this.$el.getBoundingClientRect().width) || 0;
            if (this.columnsWidth < totalWidth) rtn.width = Math.floor(totalWidth / this.currentColumns.length) + 'px';
            return rtn;
        },
        getRowClasses(row, icon = '') {
            let rtn = [],
                isCurrent = row && row[0] && row[0].value && this.currentIds.indexOf(row[0].value) >= 0;
            if (!icon) rtn = ['v-table__row', isCurrent ? 'v-table__row-selected' : ''];
            else rtn = ['icon', isCurrent ? 'icon-checkbox-o selected' : 'icon-checkbox'];
            return rtn;
        },
        getColumnClasses(col) {
            if (!col) return [];
            return [
                {
                    icons: (col.type && col.type === 'button') || (col && col['isIcon'])
                },
                col && col['align'] ? col['align'] : ''
            ];
        },
        getSelectText(cidx, col) {
            // console.log('v-table.getSelectText: ', cidx, col, this.options);
            let res = this.options[this.currentColumns[cidx].prop].find(v => v.value === col || v === col);
            return (res && res.label) || res;
        },
        // update() {
        //     console.log(`v-table.${this._uid}.update: `, this.currentValue);
        //     if (!this.readonly && !this.originalValue.length && this.value.length) {
        //         this.value.forEach(v => {
        //             let obj = {};
        //             this.currentColumns.forEach((c, ci) => {
        //                 Object.keys(c).forEach(ck => {
        //                     if (ck === 'prop') obj[c[ck]] = v[ci];
        //                 });
        //             });
        //             this.originalValue.push(obj);
        //         });
        //         // this.currentValue = this.value;
        //         // return;
        //     } else if (!this.originalValue.length) this.originalValue = [{}];
        //     // format list data...
        //     let rows = [];
        //     this.originalValue.forEach((r, ridx) => {
        //         if (r['hidden'] === true || r['hidden'] === 'true') return;

        //         let row = [];
        //         this.currentColumns.forEach(col => {
        //             if (col.prop && r[col.prop] && /Time/.test(col.prop))
        //                 row.push(Utils.getDateTimeString(r[col.prop]));
        //             else if (col.prop === 'checkbox') row.push({ type: 'button', value: r['id'] });
        //             else if (col.prop === 'properties.lock')
        //                 row.push(
        //                     r['properties'] && r['properties']['lock'] === 'true'
        //                         ? 'icon-selected selected'
        //                         : 'icon-select'
        //                 );
        //             else if (r[col.prop]) row.push(r[col.prop]);
        //             else if (col.prop === 'idx') row.push(ridx);
        //             else row.push('');
        //         });
        //         row = this.getButtons(row);
        //         rows.push(row);

        //         // if (r.id) this.currentIds[r.id] = false; // init
        //     });

        //     // this.currentValue = rows;
        //     this.currentValue = [];
        //     this.tic = new Tic(rows, i => this.currentValue.push(rows[i]));
        // },
        async getList() {
            // let rows = [];
            if (typeof this.func !== 'function') return Promise.resolve();

            let res = await this.func({ page: this.page, limit: this.limit });
            this.originalValue = this.originalValue.concat(res.list);
            // console.log(`v-table.${this._uid}.getList: `, res);
        },
        repaint() {
            // console.warn('v-table.repaint: ', this.trueName, ' -------> ', this.isActive, this);
            if (this.isActive) this.init();
        },
        // repaint: _.throttle(function () {
        //     this.getList();
        // }, process.env.VUE_APP_THROTTLE_DELAY),
        // patchData () {},
        getButtons(row) {
            if (!this.readonly) {
                row = (row || []).concat([
                    { type: 'button', prop: 'add', classes: 'btn icon icon-add' },
                    { type: 'button', prop: 'subtract', classes: 'btn icon icon-subtract' }
                ]);
            } else if (this.readonly) {
                // row = [
                //     // { type: 'icon', prop: 'select', classes: 'icon icon-checkbox' },
                //     { type: 'icon', prop: 'locked', classes: 'icon icon-lock' }
                // ].concat(row);
            }
            return row;
        },
        handleOperateClick(e, key, idx) {
            // console.warn('v-table.handleOperateClick: ', e, key, idx);
            if (key === 'subtract') this.subtractByIdx(idx);
            else if (key === 'add') this.addByIdx(idx);
        },
        getNewLine() {
            let row = [];
            this.currentColumns.forEach(v => row.push(typeof v.default !== 'undefined' ? v.default : ''));
            // row = row.concat(this.getButtons());
            return row;
        },
        isEmptyLine(row) {
            return !row.some(v => !!v);
        },
        addByIdx(idx) {
            let curs = (this.currentValue || []).concat(); // return a new one
            // console.log('v-table.addByIdx: ', idx, ', ', curs);
            if (curs.length && this.isEmptyLine(curs[idx])) return;
            let afs = curs.splice(idx + 1, (curs.length + 1) | 1);
            curs.push(this.getNewLine());
            this.currentValue = curs.concat(afs);
            console.log('v-table.addByIdx: ', idx, ', ', curs, afs, this.currentValue);
        },
        subtractByIdx(idx) {
            // console.log('v-table.subtractByIdx: ', idx);
            this.currentValue.splice(idx, 1);
            this.$nextTick(() => {
                // check, in the next event loop...
                if (this.currentValue.length < 1) this.addByIdx(0);
            });
        },
        handleSelectRow(row, ridx) {
            if (!this.readonly || !row || !row.id) return;
            // this.$emit('handleSelectRow', row);
            // this.$emit('handleSelectRow', Object.assign({}, { row, originalRow: this.originalValue[ridx] }));
            this.$emit('handleSelectRow', this.originalValue[ridx]['id']);

            if (!this.readonly || !row[0].value) return;

            let idx = this.currentIds.indexOf(row[0].value),
                hasSelected = idx >= 0;

            if (this.isAltFnActive && hasSelected) {
                this.currentIds.splice(idx, 1);
                this.selectedRowIdx = -1;
            } else if (this.isAltFnActive && !hasSelected) {
                this.currentIds.push(row[0].value);
                this.selectedRowIdx = ridx;
            } else if (!this.isAltFnActive && hasSelected) {
                this.currentIds = [];
                this.selectedRowIdx = -1;
            } else {
                this.currentIds = [row[0].value];
                this.selectedRowIdx = ridx;
                // bus.emit('p-sitemap.locateContour', row[0].value);
            }
            // console.log('v-table.handleSelectRow: ', this.selectedRowIdx);
        },
        toggleSelectAll() {
            if (!this.readonly) return;

            let tag = false;
            if ((this.currentIds.length && !this.selectedAll) || !this.currentIds.length) tag = true;
            // console.log('v-table.toggleSelectAll: ', tag);
            let cur = [];
            if (tag) this.currentValue.forEach(v => cur.push(v[0].value));
            this.currentIds = cur;
        },
        handleSort(e, key, idx) {
            if (key === 'checkbox' || key === 'properties.lock') return;
            // console.log('v-table.handleSort: ', key, idx);
            if (!this.orderBy) {
                this.orderBy = key;
                this.sortType = 'asc';
            } else if (this.orderBy !== key) {
                this.orderBy = key;
                this.sortType = 'asc';
            } else if (this.orderBy === key && this.sortType === 'asc') {
                this.orderBy = key;
                this.sortType = 'desc';
            } else {
                this.orderBy = '';
                this.sortType = '';
            }

            // if (!this.orderBy || !this.sortType) return;
            if (this.currentValue && this.currentValue.length <= 1) return 0;
            if (this.currentValue && this.currentValue.length > 1) {
                this.currentValue.sort((r1, r2) => {
                    // let cidx = this.currentColumns.findIndex(r => r.key === (this.orderBy || 'idx')),
                    let cidx = typeof idx !== 'undefined' ? idx : 'idx',
                        r1val = r1[cidx],
                        r2val = r2[cidx],
                        rtn;

                    /*
                     * Q: sentry: 排序报错
                     * A: 只有两个值都不存在或者都为空时不排序，其中一项有值则排序
                     *              -- mod by ouyang on 2020.07.23
                     */
                    if (!r1val && !r2val) return 0;

                    if (typeof r1val === 'number') rtn = r1val - r2val;
                    else if (r1val < r2val) rtn = -1;
                    else if (r1val > r2val) rtn = 1;
                    else rtn = -1;

                    if (this.sortType === 'desc') return -rtn;
                    else return rtn;
                });
            }
        }
    }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<!-- <style scoped lang="scss"> -->
<style lang="scss">
.v-table {
    .v-table__header {
        display: flex;
        /*border-left: 1px solid silver;*/
        background: #e9eaec;
        border-radius: 4px;
        overflow: hidden;
    }

    .v-table__header-item {
        /*border-top: 1px solid silver;*/
        /*border-right: 1px solid silver;*/
        padding: 5px;
        display: inline-block;
        transition: background-color 500ms;

        /* for different language fonts */
        text-align: left;
        height: 14px;
        line-height: 14px;

        &.right {
            text-align: right;
        }
        .icon-setting {
            /*font-size: 16px;*/
            /*font-weight: 700;*/
            /*color: #252d45;*/
        }
    }

    .v-table__header-item:hover {
        background-color: silver;
        transition: background-color 100ms;
    }

    .v-table__shadow {
        pointer-events: none;
        position: relative;
        top: 0;
        left: 0;
        right: 0;
        height: 0px;
        color: gray; /* this way the shadow color can be overridden */
        box-shadow: 0 6px 6px -6px inset;
        z-index: 1;
    }

    .v-table__row-box {
        /*min-height: 350px;*/
        max-height: 400px;
        /*margin-top: -10px;
        padding-top: 3px;*/
        overflow-y: scroll;
        background-color: #ffffff;
        &::-webkit-scrollbar {
            /*滚动条整体样式*/
            width: 7.6px;
            height: 7.6px;
            /*display: none;*/
        }
        &::-webkit-scrollbar-thumb {
            /*滚动条里面小方块*/
            border-radius: 3.8px;
            box-shadow: inset 0 0 3.8px rgba(0, 0, 0, 0.2);
            background: #535353;
        }
        &::-webkit-scrollbar-track {
            /*滚动条里面轨道*/
            box-shadow: inset 0 0 3.8px rgba(0, 0, 0, 0.2);
            border-radius: 3.8px;
            background: #ededed;
        }
    }

    .v-table__row {
        position: relative;
        // border: 1px solid transparent;
        display: flex;
        // margin: 4px 0;
        line-height: 24px;

        &:nth-child(odd) {
            background-color: #f2f2f4;
        }
    }

    // .v-table__row:hover:not(.v-table__row-selected) {
    //     // box-shadow: 0 0 10px silver inset;
    //     // border: 1px solid silver;
    //     // border-radius: 3px;
    //     background-color: whitesmoke;
    // }

    .v-table__row-selected {
        color: white !important;
        background-color: DimGray;
        // border: 1px solid DimGray;
        border-radius: 3px;
    }

    .v-table__row-checkbox {
        position: absolute;
        top: 1px;
        left: 4px;
        width: 11px;
        height: 11px;
        padding: 1px;
        background-color: white;
        border: 1px solid dimgray;
        box-sizing: border-box;
    }

    .v-table__row-checkbox-checked {
        // background-image: url('./assets/images/cross.svg');
        background-repeat: no-repeat;
        background-size: cover;
        background-origin: content-box;
    }

    .v-table__cell {
        display: inline-block;
        // margin-right: 4px;
        padding: 0 3px;
        margin: 0 2px;
        border-radius: 3px;
        font-size: 12px;
        // font-weight: 500;
        text-align: left;
        vertical-align: top;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        border-right: transparent 1px solid;

        &.right {
            text-align: right;
        }

        &.icons {
            text-align: center;
        }
        .icon-add,
        .icon-subtract {
            font-size: 12px;
            font-weight: 700;
            color: #252d45;
            margin-left: 5px;
        }
    }
}

.v-table.editor {
    .v-table__row {
        margin: 0;

        // &:hover {
        //     background-color: initial;
        // }

        .v-table__cell {
            box-sizing: content-box;
            margin: 0;
            border: 0;
            border-radius: 0;
            padding: 0 5px;

            &.icons {
                border: 0;
                // background: whitesmoke;
            }
        }
    }
    .v-field {
        padding: 0;

        input {
            background-color: transparent;
            font-size: 12px;
            height: 18px;
            padding: 0 3px;
            border: 0;
        }
    }
    .btn {
        border: 0;
        background: none;
        font-size: 18px;
        font-weight: 500;
        line-height: 18px;
        padding: 0;

        &:hover {
            border-color: initial;
            box-shadow: none;
            color: #daa520;
            transition: color 100ms, background-color 100ms;
        }
    }
    .p-picker-path,
    .p-picker-range {
        .icon {
            font-size: 18px;
        }
        select {
            border: none;
            background: transparent;
        }
    }
}
</style>
